package chapt03.triangle;
// Triangle.java
// OpenGL SuperBible
// Demonstrates OpenGL Triangle Fans, backface culling, and depth testing
// Program by Richard S. Wright Jr.

import javax.media.opengl.GL2;

public class Triangle
{
	// Define a constant for the value of PI
	static float GL_PI = 3.1415f;
	
	// Rotation amounts
	static float xRot = 0.0f;
	static float yRot = 0.0f;
	
	// Flags for effects
	static boolean iCull;
	static boolean iOutline;
	static boolean iDepth;
		
	///////////////////////////////////////////////////////////////////////////////
	// Reset flags as appropriate in response to menu selections
	public static void processMenu(int value)
	{
		switch(value)
		{
			case 1:
				iDepth = !iDepth;
				break;

			case 2:
				iCull = !iCull;
				break;
				
			case 3:
				iOutline = !iOutline;
				
			default:
				break;
		}		
	}
	
	// Setup the rendering state
	protected static void setupRC(GL2 gl2, int width, int height)
	{
		// Black background
		gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		
		// Set drawing color to green
		gl2.glColor3f(0.0f, 1.0f, 0.0f);
		
		// Set color shading model to flat
		gl2.glShadeModel(GL2.GL_FLAT);
		
		// Clock wise wound polygons are front facing, this is reversed
		// because we are using triangle fans
		gl2.glFrontFace(GL2.GL_CW);
	}
	
	// Called to draw scene
	protected static void renderScene(GL2 gl2, int w, int h)
	{	
		float x, y, angle; // Storage for coordinates and angles
		int iPivot = 1;    // Used to flag alternating colors
		
		// Clear the window and the depth buffer
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		
		// Turn culling on if flag is set
		if(iCull)
			gl2.glEnable(GL2.GL_CULL_FACE);
		else
			gl2.glDisable(GL2.GL_CULL_FACE);
		
		// Enable depth testing if flag is set
		if(iDepth)
			gl2.glEnable(GL2.GL_DEPTH_TEST);
		else
			gl2.glDisable(GL2.GL_DEPTH_TEST);
		
		// Draw back side as a polygon only, if flag is set
		if(iOutline)
			gl2.glPolygonMode(GL2.GL_BACK, GL2.GL_LINE);
		else
			gl2.glPolygonMode(GL2.GL_BACK, GL2.GL_FILL);
		
		// Save matrix state and do the rotation
		gl2.glPushMatrix();
		gl2.glRotatef(xRot, 1.0f, 0.0f, 0.0f);
		gl2.glRotatef(yRot, 0.0f, 1.0f, 0.0f);
		
		// Begin a triangle fan
		gl2.glBegin(GL2.GL_TRIANGLE_FAN);
		
		// Pinnacle of cone is shared vertex for fan, moved up Z axis
		// to produce a cone instead of a circle
		gl2.glVertex3f(0.0f, 0.0f, 75.0f);
		
		// Loop around in a circle and specify even points along the circle
		// as the vertices of the triangle fan
		for(angle = 0.0f; angle < (2.0 * GL_PI); angle += (GL_PI / 8.0f))
		{
			// Calculate x and y position of the next vertex
			x = 50.0f * (float)Math.sin(angle);
			y = 50.0f * (float)Math.cos(angle);
			
			// Alternate color between red and green
			if((iPivot % 2) == 0)
				gl2.glColor3f(0.0f, 1.0f, 0.0f);
			else
				gl2.glColor3f(1.0f, 0.0f, 0.0f);
			
			// Increment pivot to change color next time
			iPivot++;
			
			// Specify the next vertex for the triangle fan
			gl2.glVertex2f(x, y);
		}
		
		// Done drawing fan for cone
		gl2.glEnd();
		
		// Begin a new triangle fan to cover the bottom
		gl2.glBegin(GL2.GL_TRIANGLE_FAN);
		
		// Center of fan is at the origin
		gl2.glVertex2f(0.0f, 0.0f);
		for(angle = 0.0f; angle < (2.0f * GL_PI); angle += (GL_PI / 8.0f))
		{
			// Calculate x and y position of the next vertex
			x = 50.0f * (float)Math.sin(angle);
			y = 50.0f * (float)Math.cos(angle);
			
			// Alternate color between red and green
			if((iPivot % 2) == 0)
				gl2.glColor3f(0.0f, 1.0f, 0.0f);
			else
				gl2.glColor3f(1.0f, 0.0f, 0.0f);
			
			// Increment pivot to change color next time
			iPivot++;
			
			// Specify the next4 vertex for the triangle fan
			gl2.glVertex2f(x, y);
		}
		
		// Done drawing the fan that covers the bottom
		gl2.glEnd();
		
		// Restore transformations
		gl2.glPopMatrix();
		
		gl2.glFlush();
	}
	
	public static void changeSize(GL2 gl2, int w, int h)
	{
		float nRange = 100.0f;
		
		// Prevent a divide by zero
		if(h == 0)
			h = 1;
		
		// Set Viewport to window dimensions
		gl2.glViewport(0, 0, w, h);
		
		// Reset coordinate system
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Establish clipping volume (left, right, bottom, top, near, far)
		if(w <= h)
			gl2.glOrtho(-nRange, nRange, -nRange * h / w, nRange * h / w, -nRange, nRange);
		else
			gl2.glOrtho(-nRange * w / h, nRange * w / h, -nRange, nRange, -nRange, nRange);
		
		// Reset Model view matrix stack
		gl2.glMatrixMode(GL2.GL_MODELVIEW);
		gl2.glLoadIdentity();		
	}
}